<template>
    <div class="circle-box" :style="{width: circleSize.width+'px',height: circleSize.height+'px'}">
        <canvas :width="circleSize.width+'px'" :height="circleSize.height+'px'" class="canvas-box stroke-canvas" id="BgCanvas"></canvas>
        <canvas :width="circleSize.width+'px'" :height="circleSize.height+'px'" class="canvas-box trail-canvas" id="InCanvas"></canvas>
        <div class="slot">
            <!--进度环内部槽-->
            <slot></slot>
        </div>
    </div>
</template>

<script lang="ts">
    import {Component, Prop, Vue, Watch, Emit} from "vue-property-decorator";

    @Component({components: {}})
    // 圆环进度
    export default class CircleSchedule extends Vue {
        // 进度条进度
        @Prop({default: 0, type: Number})
        private percent!: number;
        // 图表的宽度和高度
        @Prop({default: 90, type: Number})
        private size!: number;
        //进度环背景的线宽
        @Prop({default: 7, type: Number})
        private lineWidth!: number;
        //进度环前景的线宽
        @Prop({default: 7, type: Number})
        private strokeWidth!: number;
        //进度环背景的颜色
        @Prop({default: "#2d8cf0", type: String})
        private lineColor!: string;
        //进度环前景的颜色
        @Prop({default: "#ff0000", type: String})
        private strokeColor!: string;
        //仪表盘
        @Prop({default: false, type: Boolean})
        private dashboard!: boolean;
        // 仪表盘起始角度
        @Prop({default: 27, type: Number})
        private start!: number;


        private selfPercent: number = 0;
        private type: string = "add";
        private timer: number = 0;
        private bgId: string = "BgCanvas";
        private inId: string = "InCanvas";

        private get circleSize(): { width: number, height: number } {
            const clientCircleSize = this.fitUnit(this.size);
            return {width: clientCircleSize, height: clientCircleSize};

        }

        private get centerX(): number {
            return this.circleSize.width / 2;
        }

        private get centerY(): number {
            return this.circleSize.height / 2;
        }

        private get radius(): number {
            return this.centerX - this.strokeWidth - Math.abs(this.strokeWidth - this.lineWidth);
        }

        private get startDeg(): number {
            return Math.PI * (1 - this.start / 180);
        }

        private get countDeg(): number {
            return this.start * 2 + 180;
        }

        private get rad(): number {
            return Math.PI * 2 / 100;
        }


        private get bgDegArr(): { start: number, end: number } {
            let start, end;
            if (this.dashboard) {
                start = this.startDeg;
                end = Math.PI * this.countDeg / 180 + this.startDeg;
            } else {
                start = 0;
                end = Math.PI * 2;
            }
            return {start, end};
        }

        private get fillDegArr(): { start: number, end: number } {
            let start, end;
            if (this.dashboard) {
                start = this.startDeg;
                end = Math.PI * this.selfPercent / 100 * this.countDeg / 180 + this.startDeg;
            } else {
                start = -Math.PI / 2;
                end = -Math.PI / 2 + this.selfPercent * this.rad;
            }
            return {start, end};
        }


        @Watch("percent")
        private watchPercent(newValue: number, oldValue: number) {
            if (newValue > oldValue) {
                this.type = "add";
            } else {
                this.type = "reduce";
            }
            this.$nextTick(() => {
                this.init();
            });
        }

        private fitUnit(num: number) {
            return num / 375 * document.body.clientWidth;
        }

        private init() {
            this.backgroundCircle();
            this.requestAnimationFrame();
        }

        private mounted(): void {
            this.init();
        }


        private backgroundCircle(): void {
            const canvas = document.getElementById(this.bgId);
            const context = (<any> canvas).getContext("2d");

            (<any> canvas).width = this.circleSize.width;
            (<any> canvas).height = this.circleSize.height;

            context.lineWidth = this.fitUnit(this.lineWidth);
            context.lineCap = "round";
            context.strokeStyle = this.lineColor;
            context.beginPath();
            context.arc(this.centerX, this.centerY, this.radius, this.bgDegArr.start, this.bgDegArr.end, false);
            context.stroke();
        }

        private foregroundCircle() {
            const canvas = document.getElementById(this.inId);
            const context = (<any> canvas).getContext("2d");

            (<any> canvas).width = this.circleSize.width;
            (<any> canvas).height = this.circleSize.height;

            context.lineWidth = this.fitUnit(this.strokeWidth);
            context.lineCap = "round";
            context.strokeStyle = this.strokeColor;
            context.beginPath();
            context.arc(this.centerX, this.centerY, this.radius, this.fillDegArr.start, this.fillDegArr.end, false);
            context.stroke();
        }


        private requestAnimationFrame(): void {
            if (this.type == "add") {
                if (this.selfPercent >= this.percent) {
                    clearTimeout(this.timer);
                    return;
                }
                this.selfPercent++;
                if (this.selfPercent >= 100) {
                    this.selfPercent = 100;
                }
            } else {
                if (this.selfPercent <= this.percent) {
                    clearTimeout(this.timer);
                    return;
                }
                this.selfPercent--;
                if (this.selfPercent <= 0) {
                    this.selfPercent = 0;
                }
            }
            this.foregroundCircle();
            this.timer = setTimeout(this.requestAnimationFrame, 5);
        }
    }
</script>

<style scoped lang="stylus">
    .circle-box
        margin auto;
        position relative;
        overflow hidden

    .slot
        width 100%;
        height 100%;
        position absolute;
        top 0;
        left 0;

    .canvas-box
        position absolute;
        top 0;
        left 0;
        display flex;
        justify-content center;
        align-items center;


</style>
